﻿#include "hash_table.h"

 hash_t get_hash(unsigned char * key, unsigned int len)
{
	 len = (len == 2) ? 1 : len;
	unsigned char  *buf = key;
	hash_t hash = 5381;
	while (len--)
	{
		hash = (((hash << 5) + hash) + *buf++);
	}
	return hash;
}

table_t * create_table(unsigned int size)
{
	table_t* table = (table_t*)malloc(sizeof(table_t));
	table->lists = (list_header_t*)malloc(sizeof(list_header_t)*size);
	table->lists_count = size;
	int err = pthread_rwlock_init(&table->rwlock, NULL);
	if (err != 0)
	{
		perror("create_table rwlock error ");
		free(table->lists);
		free(table);
		return NULL;
	}
	int i;
	for (i = 0 ; i< size; i++)
	{
		table->lists[i].list = NULL;
		int err = pthread_rwlock_init(&(table->lists[i].rwlock), NULL);
		if (err != 0)
		{
			perror("create_table rwlock error ");
			free(table->lists);
			free(table);
			return NULL;
		}
	}
	
	return table;
}

node_t* create_node(unsigned char* key,unsigned int key_len)
{
	node_t *target = (node_t*)malloc(sizeof(node_t) + key_len);
	if (!target)
		return NULL;
	target->key = ((unsigned char*)target) + sizeof(node_t);
	target->next = NULL;
	target->previous = NULL;
	target->value = NULL;
	memcpy(target->key, key, key_len);
	return target;
}


int insert_to_table(table_t * table, unsigned char *key, unsigned int key_len, void * val, hash_t hash)
{
	if (!table || !key || table->lists_count==0 || key_len == 0)
		return 0;
	hash = (hash > 0) ? hash : get_hash(key, key_len);
	list_header_t* header =  &table->lists[hash%table->lists_count];
	node_t*node = header->list;
	node_t* target = NULL;
	pthread_rwlock_wrlock(&header->rwlock);
	for (;node != NULL;node = node->next)
	{
		if (strcmp(key,node->key)== 0 )
		{
			target = node;
			break;
		}
		if (!node->next) //最后一个节点时跳出，
			break;
	}

	if (!target)
	{
		target = create_node(key, key_len);
		if (header->list == NULL)
		{
			header->list = target;
		}	
		else {
			node->next = target;
			target->previous = node;
		}
	}
	
	int ret = (table->add_value)(&target->value,target->key,val);
	pthread_rwlock_unlock(&header->rwlock);
	return ret;
	
}

void * find_from_table(table_t * table, unsigned char * key, unsigned int key_len, hash_t hash)
{
	if (!table || !table->lists || table->lists_count == 0)
	{
		return NULL;
	}
	hash = (hash > 0) ? hash : get_hash(key, key_len);

	list_header_t* header = &table->lists[hash%table->lists_count];
	node_t*node = header->list;
	node_t* target = NULL;
	void * val = NULL;
	pthread_rwlock_rdlock(&header->rwlock);
	for (; node != NULL; node = node->next)
	{
		if (strcmp(key, node->key) == 0)
		{
			val =  node->value;
		}
	}
	pthread_rwlock_unlock(&header->rwlock);
	return val;
}

void * take_from_table(table_t * table, unsigned char * key, unsigned int key_len, hash_t hash)
{
	hash = (hash > 0) ? hash : get_hash(key, key_len);
	list_header_t* header = &table->lists[hash%table->lists_count];
	node_t*node = header->list;
	if (!node)
	{
		return NULL;
	}
	node_t* target = NULL;
	void *val = NULL;
	pthread_rwlock_wrlock(&header->rwlock);

	for (; node != NULL; node = node->next)
	{
		if (strcmp(key, node->key) == 0)
		{
			val = node->value;
			if (node->previous)
			{
				node->previous->next = node->next;
				if (node->next)
					node->next->previous = node->previous;
			}
			else
			{
				header->list = node->next;
				if (node->next)
					node->next->previous = NULL;
			}
			free(node);
			break;
		}
	}
	pthread_rwlock_unlock(&header->rwlock);
	return val;
}



void* pop_from_table(table_t* table, hash_t index)
{

	list_header_t*  header = &table->lists[index];
	pthread_rwlock_wrlock(&header->rwlock);
	void*value = NULL;
	node_t* node = header->list;
	if (node)
	{
		header->list = header->list->next;
		value = node->value;
		free(node);
	}
	pthread_rwlock_unlock(&header->rwlock);
	return value;
}





void * next(table_t * table)
{
		pthread_rwlock_rdlock(&table->rwlock);
		table->pos_node = table->pos_node->next;
		if (!table->pos_node)  //一个桶遍历完了跳转到下一下桶
		{
			table->lists_index++;
			table->pos_node = table->lists[table->lists_index].list;
		}
		pthread_rwlock_unlock(&table->rwlock);
		return table->pos_node;
}

void * start(table_t * table)
{
	pthread_rwlock_rdlock(&table->rwlock);
	table->lists_index = 0;
	table->pos_node = table->lists[table->lists_index].list;
	pthread_rwlock_unlock(&table->rwlock);
	return table->pos_node;
}



